package ministock;

import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.LinkedBlockingQueue;

import weibo4j.Comment;
import weibo4j.Weibo;
import weibo4j.WeiboException;

import com.google.code.ministock.Stock;

/**
 * @author Zhang, Guilin
 * 2010-11-3
 */
public class MiniStock {
	
	static final String SUBSCRIPTION_DATABASE = "3548802161";
	
	private static Properties config;
	
	private static volatile boolean stopped;
	
	private static Agent commentConsumer;
	
	private static Agent commentProducer;
	
	private static Agent subscriptionProducer;
	
	private static ConcurrentMap<String, List<Subscription>> subscriptionsMap;
	
	private static BlockingQueue<Stock> stocks;
	
	private MiniStock() {
	}
	
	static {
		initializeConfigurations();
	}
	
	public static void main(String[] args) {
		try {
			MiniStock.startup();
		} catch(Exception e) {
			e.printStackTrace();
			MiniStock.shutdown();
		}
	}
	
	
	public static void startup() throws WeiboException {
		subscriptionsMap = loadSubscriptions();
		stocks = new LinkedBlockingQueue<Stock>();
		commentConsumer = new CommentConsumer(subscriptionsMap, stocks, stopped);
		commentProducer = new CommentProducer(subscriptionsMap, stocks, stopped);
		subscriptionProducer = new SubscriptionProducer(subscriptionsMap, stocks, stopped);
		new Thread(commentConsumer).start();
		new Thread(commentProducer).start();
		new Thread(subscriptionProducer).start();
	}
	
	private static ConcurrentMap<String, List<Subscription>> loadSubscriptions() throws WeiboException {
		ConcurrentMap<String, List<Subscription>> map = new ConcurrentHashMap<String, List<Subscription>>();
		Weibo weibo = MyWeibo.getInstance();
		List<Comment> comments = weibo.getComments(SUBSCRIPTION_DATABASE);
		if(comments != null && !comments.isEmpty()) {
			for(Comment comment : comments) {
				String text = comment.getText();
				boolean unsub = text.startsWith("-");
				if(unsub) {
					text = text.substring(1);
				}
				Subscription sub = Subscription.valueOf(text);
				List<Subscription> list = getSubscriptions(map, sub.getStockName());
				if(unsub) {
					list.remove(sub);
					// TODO bug here, subscription not equals because of dif status
					// TODO bug here, remove should be late than add always.
				} else {
					list.add(sub);
				}
			}
		}
		return map;
	}
	
	public static void shutdown() {
		stopped = true;
	}

	private static void initializeConfigurations() {
		config = new Properties();
		InputStream in = null;
		try {
			in = MiniStock.class.getClassLoader().getResourceAsStream("ministock.properties");
			config.load(in);
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(-1);
		} finally {
			if(in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static List<Subscription> getSubscriptions(ConcurrentMap<String, List<Subscription>> map, String stockName) {
		List<Subscription> list = map.get(stockName);
		if(list == null) {
			list = new LinkedList<Subscription>();
			List<Subscription> exist = map.putIfAbsent(stockName, list);
			if(exist != null) {
				list = exist;
			}
		}
		return list;
	}
	
	public static String getConsumerKey() {
		return config.getProperty("consumer.key");
	}
	
	public static String getConsumerSecret() {
		return config.getProperty("consumer.secret");
	}
	
	public static String getUserKey() {
		return config.getProperty("user.key");
	}
	
	public static String getUserSecret() {
		return config.getProperty("user.secret");
	}
	
	public static long getSubscriptionScanPeriod() {
		String period = config.getProperty("subscription.period", "300000");
		return Long.valueOf(period);
	}


	public static long getCommentPeriod() {
		String period = config.getProperty("comment.period", "1200000");
		return Long.valueOf(period);
	}
	
	public static int getOpenningHour() {
		String opennning = config.getProperty("market.openning", "9");
		return Integer.parseInt(opennning);
	}
	
	public static int getClosingHour() {
		String closing = config.getProperty("market.closing", "16");
		return Integer.parseInt(closing);
	}
}
